package com.example.demo.controller;

import com.alibaba.fastjson.JSONObject;
import com.example.demo.common.*;
import com.example.demo.entity.vo.LoginerVO;
import com.example.demo.verify.NoEmpty;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.f4b6a3.ulid.UlidCreator;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.util.StopWatch;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/redis")
@Api(tags = "11、redis管理")
@ApiSupport(author = "罗海林", order = 11)
@Validated
@RequiredArgsConstructor
public class RedisController {

    private final RedisTemplate<String, String> redis;
    private final RedisService redisService;

    private Cache<String, String> cache;

    @PostMapping("/getRedisID")
    @ApiOperation(value = "获取redis唯一ID", response = Result.class)
    @ApiOperationSupport(author = "罗海林", order = 2)
    public Result getRedisID() {
        long id = redisService.generateId("luohailin");

        Result res = new Result();
        res.ok();
        res.put("id", id);
        return res;
    }

    @PostMapping("/getULID")
    @ApiOperation(value = "获取ULID", response = Result.class)
    @ApiOperationSupport(author = "罗海林", order = 3)
    public Result getULID() {
        Result res = new Result();
        res.ok();
        res.put("id1", UlidCreator.getMonotonicUlid(1670837655000L).toString());
        res.put("id2", UlidCreator.getMonotonicUlid(1670837655000L).toString());
        res.put("id3", UlidCreator.getMonotonicUlid(1670837655000L).toString());
        res.put("ulid_Monotonic1", UlidCreator.getMonotonicUlid().toString());
        res.put("ulid_Monotonic2", UlidCreator.getMonotonicUlid().toString());
        res.put("ulid_Monotonic3", UlidCreator.getMonotonicUlid().toString());
        res.put("ulid1", Func.getULID());
        res.put("ulid2", Func.getULID());
        res.put("ulid3", Func.getULID());
        res.put("uuid", Func.getUUID());
        return res;
    }

    @PostMapping("/getSnowflakeId")
    @ApiOperation(value = "获取雪花ID", response = Result.class)
    @ApiOperationSupport(author = "罗海林", order = 4)
    public Result getSnowflakeId() {
        // 创建一个雪花 ID 生成器实例，传入节点 ID（必须唯一性）
        SnowflakeId idGenerator = new SnowflakeId(1);
        // 生成 ID
        long id = idGenerator.generateId();

        Result res = new Result();
        res.ok();
        res.put("id", id);
        return res;
    }

    @PostMapping("/getTime")
    @ApiOperation(value = "获取执行时间", response = Result.class)
    @ApiOperationSupport(author = "罗海林", order = 5)
    public Result getTime() throws Exception {
        StopWatch sw = new StopWatch();
        sw.start("王彦远");
        Thread.sleep(2000);
        sw.stop();
        sw.start("伍莹莹");
        Thread.sleep(2000);
        sw.stop();

        System.out.println(sw.getTotalTimeMillis());
        System.out.println(sw.prettyPrint());
        System.out.println(sw.shortSummary());
        System.out.println(sw.getTaskCount());
        return null;
    }

    @PostMapping("/setObject")
    @ApiOperation(value = "保存对象数据", response = Result.class)
    @ApiOperationSupport(author = "罗海林", order = 6)
    public Result setObject() {
        String key = "object:string:";
        JSONObject js = new JSONObject();
        js.put("userid", "0507100229");
        js.put("name", "罗海林");
        js.put("age", "38");

        redis.opsForValue().set(key + "0507100229", js.toJSONString(), 1, TimeUnit.DAYS);

        js.put("userid", "0507100230");
        js.put("name", "王彦远");
        js.put("age", "33");

        redis.opsForValue().set(key + "0507100230", js.toJSONString(), 1, TimeUnit.DAYS);

        Result res = new Result();
        res.ok();
        return res;
    }

    @PostMapping("/getObject")
    @ApiOperation(value = "获取对象数据", response = Result.class)
    @ApiOperationSupport(author = "罗海林", order = 7)
    public Result getObject(@NoEmpty(message = "用户ID不能为空") @RequestParam String userId) {
        String key = "object:string:" + userId;
        String value = redis.opsForValue().get(key);
        JSONObject js = null;
        LoginerVO loginer = new LoginerVO();

        if (!Valid.isEmpty(value)) {
            js = JSONObject.parseObject(value);
            loginer.setLoginer(js);
        }

        Result res = new Result();
        res.ok();
        res.put("oldData", value);
        res.put("newData", js);
        res.put("object", loginer);
        res.put("name", loginer.getName());
        return res;
    }

    @PostMapping("/setCaffeine")
    @ApiOperation(value = "设置缓存数据", response = Result.class)
    @ApiOperationSupport(author = "罗海林", order = 8)
    public Result setCaffeine() {
        cache = Caffeine.newBuilder()
                // 初始容量
                .initialCapacity(5)
                // 最大缓存数，超出淘汰
                .maximumSize(10)
                // 设置缓存写入间隔多久过期
                .expireAfterWrite(3, TimeUnit.SECONDS)
                // 设置缓存最后访问后间隔多久淘汰，实际很少用到
                //.expireAfterAccess(3, TimeUnit.SECONDS)
                .build();

        cache.put("userName", "张三");

        Result res = new Result();
        return res.ok();
    }

    @PostMapping("/getCaffeine")
    @ApiOperation(value = "获取缓存数据", response = Result.class)
    @ApiOperationSupport(author = "罗海林", order = 9)
    public Result getCaffeine() {

        String value = cache.get("userName", (key) -> {
            // 如果key不存在，会执行回调方法
            return "userName 已过期";
        });

        Result res = new Result();
        res.ok();
        res.put("key", value);
        return res;
    }

    @PostMapping("/executeLua")
    @ApiOperation(value = "执行LUA脚本文件", response = Result.class)
    @ApiOperationSupport(author = "罗海林", order = 10)
    public Result executeLua() throws IOException {
        // 获取LUA脚本内容
        String luaPath = Func.getRootPath() + "/file/script/delkey.lua";
        String script = new String(Files.readAllBytes(Paths.get(luaPath)));
        // 执行 lua 脚本
        DefaultRedisScript<String> redisScript = new DefaultRedisScript<>(script, String.class);
        // 参数一：redisScript，参数二：key列表，参数三：arg（可多个）
        String lockKey = "lhlysyl";
        String value = "天王星";
        String result = redis.execute(redisScript, Collections.singletonList(lockKey), value);

        Result res = new Result().ok();
        res.put("result", result);
        return res;
    }

}
